#undef  xuser
#define xuser mixc::net_private_udp::inc
#include"net/udp.hpp"
#include<arpa/inet.h>
#include<errno.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>

namespace mixc::net_udp::origin::udp{
    bstate_t p2p_v4::open(reuse_address_t mode) const {
        return base_net::open(sock_type_t::ipv4_dgram, mode);
    }

    bstate_t p2p_v4::open_with_bind(ipv4 ip, u16 port, reuse_address_t mode) const {
        return base_net::open_with_bind(sock_type_t::ipv4_dgram, ip, port, mode);
    }

    bstate_t p2p_v4::bind(ipv4 ip, u16 port) const {
        return base_net::bind(ip, port);
    }

    uxx p2p_v4::read(voidp buffer, uxx bytes, ip_port_pair_v4 * from) const {
        if (m_fd <= 0){
            return 0;
        }

        auto size           = socklen_t(sizeof(sockaddr_in));
        auto addr           = sockaddr_in{};
        auto real_bytes     = recvfrom(m_fd, buffer, bytes, MSG_NOSIGNAL, (sockaddr *)& addr, & size);

        if (errno == EPIPE){
            return 0;
        }

        if (auto & pair = *from; from != nullptr){
            pair->ip->from_net(addr.sin_addr.s_addr);
            pair->port->from_net(addr.sin_port);
        }
        return real_bytes < 0 ? 0 : uxx(real_bytes);
    }

    uxx p2p_v4::write(void const * buffer, uxx bytes, ip_port_pair_v4 const & to) const {
        if (m_fd <= 0){
            return 0;
        }

        auto size           = socklen_t(sizeof(sockaddr_in));
        auto addr           = sockaddr_in{
            .sin_family = (u16)(AF_INET),
            .sin_port = to->port->net_form,
            .sin_addr = { to->ip->net_form },
            .sin_zero = {}
        };
        auto real_bytes     = sendto(m_fd, buffer, bytes, MSG_NOSIGNAL, (sockaddr *)& addr, size);

        if (errno == EPIPE){
            return 0;
        }
        return real_bytes < 0 ? 0 : uxx(real_bytes);
    }
}
